{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Python Introduction\n",
    "##### Created by Professor Eric Larson, contact at eclarson@smu.edu for errors or questions\n",
    "\n",
    "In this notebook, we will introduce the basics of programming in python as well as the installation of different modules and libraries. Debugging in python can be a pain, but there are many different ways of debugging depending on what you are most comfortable with. \n",
    "\n",
    "We will go over:\n",
    "+ Analysing and debugging errors \n",
    "+ Setting breakpoints with pdb \n",
    "+ Using an IDE with python that can look at memory, set breakpoints, etc.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "![Guido Von Rossum](https://raw.githubusercontent.com/eclarson/DataMiningNotebooks/master/data/guido.png)\n",
    "\n",
    "Python was founded by a guy named Guido Von Rossum in 1989. I will let him explain his motivations.\n",
    "From wikipedia:\n",
    ">Over six years ago, in December 1989, I was looking for a \"hobby\" programming project that would keep me occupied during the week around Christmas. My office ... would be closed, but I had a home computer, and not much else on my hands. I decided to write an interpreter for the new scripting language I had been thinking about lately: a descendant of ABC that would appeal to Unix/C hackers. I chose Python as a working title for the project, being in a slightly irreverent mood (and a big fan of Monty Python's Flying Circus).\n",
    "\n",
    "        -Guido van Rossum in 1996\n",
    "\n",
    "So let that be a lesson! Python is not named after the snake, it is after Monty Python. However, even though the language is a bit quirky, do not let that fool you. It is absolutely made for people to use as a serious programming language and tool. Whether you have novice programming skills or are a sesoned veteran at OOP. \n",
    "\n",
    "For example, take a look at the most popular programming languages as identified by the number of projects in GitHub, and the number of related questions on stack overflow. Notice the other langauges next to python, like java, php, c++, ruby, and all the heavy hitters. Its also on every top ten list of programming languages needed to get a job in programming. Check it out. Graphic credit given to RedMonk.\n",
    "![Python](https://raw.githubusercontent.com/eclarson/DataMiningNotebooks/master/data/python_ranking.png)\n",
    "\n",
    "Moreover, python is one of the fastest growing languages used in scientific computing and data science. According to a recent survey, the three most helpful languages or packages for doing data science are R, SAS, and python. You will likely make use of all three for a given project or set of projects. See http://www.r-bloggers.com/data-science-toolbox-survey-results-surprise-r-and-python-win/ for a high level description of the survey.\n",
    "\n",
    "# Running Python\n",
    "Python can be run in various ways. We will cover how to run it from the interpreter prompt, command line scripts, and from iPython notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# this is a comment\n",
    "\n",
    "# place this at the top of python file to enable running as >>./filename.py\n",
    "#! /usr/bin/python\n",
    "\n",
    "# otherwise you can run with >>python filename.py {or} >>python27 filename.py\n",
    "\n",
    "# those commands can be run from a terminal window"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello world\n"
     ]
    }
   ],
   "source": [
    "# hello world from iPython Notebook\n",
    "print(\"hello world\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Syntax\n",
    "Okay, so lets first dive into some of the syntax in python programming."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Variable type examples:\n",
      "<class 'int'>\n",
      "<class 'int'>\n",
      "<class 'float'>\n",
      "<class 'bool'>\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "# ============================================\n",
    "# Variables Example\n",
    "int_val = 8\n",
    "long_val = 23423423235 # this will now be an int\n",
    "float_val = 2.546923764237654239\n",
    "bool_val = False\n",
    "\n",
    "print (\"Variable type examples:\")\n",
    "print (type(int_val))\n",
    "print (type(long_val)) # longs are ints bit in python 3\n",
    "print (type(float_val))\n",
    "print (type(bool_val))\n",
    "\n",
    "# testing for the type of a variable\n",
    "temp = isinstance(float_val,float)\n",
    "print (temp)\n",
    "print (isinstance(float_val,int))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Arithmetic examples:\n",
      "2.6666666666666665\n",
      "2.6666666666666665\n",
      "2.6666666666666665\n",
      "2\n",
      "False\n",
      "False\n",
      "True\n",
      "8.0\n",
      "5\n",
      "81\n"
     ]
    }
   ],
   "source": [
    "#============================================\n",
    "# Arithmetic and casting\n",
    "print (\"\\nArithmetic examples:\")\n",
    "print (8 / 3)\n",
    "print (float(8) / 3)\n",
    "print (float(8) / float(3))\n",
    "print (8//3) # must explicitly ask for truncation\n",
    "\n",
    "print (True and False)  # logicals\n",
    "print (8 == 3 )  # logical equallty\n",
    "print (5 <= 6 )  # logical comparison\n",
    "\n",
    "print (2.0*4.0)  # multiplication\n",
    "print (65%6   ) # remainder, modulus\n",
    "print (3**4   ) # 3 to the fourth power"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "String example:\n",
      "A string is double or single quotes\n",
      "Three quote means that the string goes over\n",
      "multiple lines\n",
      "This also spans multiple lines but has no newline\n"
     ]
    }
   ],
   "source": [
    "#============================================\n",
    "# strings example\n",
    "print (\"\\nString example:\")\n",
    "str_val = \"A string is double or single quotes\"\n",
    "str_val_long = '''Three quote means that the string goes over\n",
    "multiple lines'''\n",
    "str_val_no_newline = '''This also spans multiple lines \\\n",
    "but has no newline'''\n",
    "\n",
    "print (str_val)\n",
    "print (str_val_long)\n",
    "print (str_val_no_newline)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A\n",
      "tr\n",
      "s\n",
      "uotes\n",
      "A string is double or single quotes\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "'str' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-10-db4b305f836f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0mprint\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mstr_val\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mstr_val\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# print the first five elements, then from the fifth and on\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0mstr_val\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'G'\u001b[0m \u001b[0;31m# this is an error, strings are immutable once they are set\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: 'str' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "# string can be accessed in a variety of different ways\n",
    "\n",
    "print (str_val[0]  ) # initial element \"0th\" element\n",
    "print (str_val[3:5]) # elements 3 and 4, but not 5\n",
    "print (str_val[-1] ) # the last element in the string\n",
    "print (str_val[-5:]) # the last five elements\n",
    "print (str_val[0:5] + str_val[5:]) # print the first five elements, then from the fifth and on\n",
    "\n",
    "str_val[5] = 'G' # this is an error, strings are immutable once they are set"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A string is double or single quotesA string is double or single quotes\n",
      "True\n",
      "Eric\n",
      "a string is double or single quotes\n",
      "A STRING IS DOUBLE OR SINGLE QUOTES\n",
      "['this', ' is', ' separated', ' by', ' commas']\n"
     ]
    }
   ],
   "source": [
    "# some common operations for strings\n",
    "print (str_val*2        ) # mutliply is like adding the number of times, here it repeats the string twice\n",
    "print ('Python' > 'Java') # compare the strings alphabetically \n",
    "\n",
    "print (\"eric\".capitalize()  )# the dot operator works like it does in most other OOP languages\n",
    "print (str_val.lower())\n",
    "print (str_val.upper())\n",
    "print (\"this, is, separated, by, commas\".split(',')) # this results is returned as a list, which we need to talk about!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tuples, Lists, Sets, and Dictionaries "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[45, 67, 'not a number', 'A string, appended as a new element in the list']\n",
      "[45, 67, 'not a number', 'A string, appended as a new element in the list', ['a list', 'within another list', 442]]\n",
      "['a list', 'within another list', 442]\n",
      "['A string, appended as a new element in the list', ['a list', 'within another list', 442]]\n"
     ]
    }
   ],
   "source": [
    "# A List is one of the most powerful tools in python from which\n",
    "# most abstract types get created and implemented\n",
    "\n",
    "# a list is very much like the mutable version of a tuple\n",
    "# it can hold any type of information\n",
    "a_list = [45, 67, \"not a number\"]\n",
    "\n",
    "# we can add to a list through the append function\n",
    "a_list.append(\"A string, appended as a new element in the list\")\n",
    "\n",
    "print (a_list)\n",
    "\n",
    "# Lists can have other lists in them\n",
    "tmp_list = [\"a list\", \"within another list\", 442]\n",
    "a_list.append(tmp_list)\n",
    "\n",
    "print (a_list)\n",
    "\n",
    "# all of the indexing we learned from before still works with lists\n",
    "print (a_list[-1])\n",
    "print (a_list[-2:])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(45, 67, 'not a number')\n",
      "not a number\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "'tuple' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-13-a10b9f1d25cc>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      8\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      9\u001b[0m \u001b[0;31m# but you cannot change a tuple, its immutable!!\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m \u001b[0ma_tuple\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'hey'\u001b[0m \u001b[0;31m# this will give you an error!!\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "# tuples are immutable lists and are designated by commas\n",
    "# you can store ANYTHING in side a tuple, its basically a complex object container\n",
    "a_tuple = 45, 67, \"not a number\" \n",
    "print (a_tuple)\n",
    "\n",
    "# you can access a tuple with square brackets\n",
    "print (a_tuple[2])\n",
    "\n",
    "# but you cannot change a tuple, its immutable!!\n",
    "a_tuple[2] = 'hey' # this will give you an error!!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'pear', 'banana', 'apple', 'orange'}\n",
      "True\n",
      "False\n",
      "{'c', 'r', 'd', '!', 'b', 'a'}\n",
      "{'r', '!', 'b', 'd'}\n",
      "{'z', 'c', 'r', 'd', '!', 'b', 'm', 'l', 'a'}\n",
      "{'c', 'a'}\n",
      "{'z', 'r', 'd', '!', 'b', 'm', 'l'}\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'frozenset' object has no attribute 'add'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-14-936e0972b751>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     20\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     21\u001b[0m \u001b[0ma_immutable\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfrozenset\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 22\u001b[0;31m \u001b[0ma_immutable\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'e'\u001b[0m\u001b[0;34m)\u001b[0m   \u001b[0;31m# the set is immutable, so we cannot add to it, this will give an error!\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'frozenset' object has no attribute 'add'"
     ]
    }
   ],
   "source": [
    "# Sets, taken from the Python sets tutorial\n",
    "# https://docs.python.org/2/tutorial/datastructures.html#sets\n",
    "basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']\n",
    "fruit = set(basket) # create a set without duplicates\n",
    "print (fruit)\n",
    "print ('orange' in fruit   ) # fast membership testing\n",
    "print ('crabgrass' in fruit)\n",
    "\n",
    "# Demonstrate set operations on unique letters from two words\n",
    "a = set('abracadabra')\n",
    "b = set('alacazam')\n",
    "a.add('!') # also add the some punctuation\n",
    "\n",
    "# set operations\n",
    "print (a    )   # unique letters in a\n",
    "print (a - b)   # letters in a but not in b\n",
    "print (a | b)   # letters in either a or b\n",
    "print (a & b)   # letters in both a and b\n",
    "print (a ^ b)   # letters in a or b but not both\n",
    "\n",
    "a_immutable = frozenset(a)\n",
    "a_immutable.add('e')   # the set is immutable, so we cannot add to it, this will give an error!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'cat': 4, 'dog': 4, 'human': 2}\n",
      "4\n",
      "2\n",
      "===============\n",
      "{'bird': 'two and some wings', 'dog': 4, 45: 'a key that is not a string', 'human': 'two'}\n"
     ]
    }
   ],
   "source": [
    "# Dictionaries map keys to values.\n",
    "\n",
    "# Here we setup a key as a string and the value as a number\n",
    "num_legs = { 'dog': 4, 'cat': 4, 'human': 2 }\n",
    "\n",
    "# You access Subscripts via the \"key\"\n",
    "print (num_legs)\n",
    "print (num_legs['dog'])\n",
    "print (num_legs['human'])\n",
    "\n",
    "print ('===============')\n",
    "# Entries can be added, updated, or deleted.\n",
    "# Again, these are just containers for any memory type\n",
    "num_legs['human'] = 'two'\n",
    "num_legs['bird'] = 'two and some wings'\n",
    "num_legs[45] = 'a key that is not a string' # notice that the key does not need to be a string\n",
    "# the key just needs to be some immutable memory\n",
    "\n",
    "del num_legs['cat']\n",
    "print (num_legs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ADTs, Loops, and Conditionals"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "for loop output:\n",
      "DataMining <class 'str'>\n",
      "This statement is in the loop\n",
      "8 <class 'int'>\n",
      "This statement is in the loop\n",
      "23423423235 <class 'int'>\n",
      "This statement is in the loop\n",
      "2.546923764237654 <class 'float'>\n",
      "This statement is in the loop\n",
      "False <class 'bool'>\n",
      "This statement is in the loop\n",
      "This statement is outside the loop\n"
     ]
    }
   ],
   "source": [
    "\n",
    "#============================================\n",
    "# for loop example with list\n",
    "print (\"\\nfor loop output:\")\n",
    "\n",
    "list_example = [int_val, long_val, float_val, bool_val]\n",
    "list_example.insert(0, \"DataMining\")\n",
    "\n",
    "# notice that the loop ends with a colon and \n",
    "# is designated by the tab alignment\n",
    "for val in list_example:\n",
    "    print (str(val) + ' ' + str(type(val)))\n",
    "    print (\"This statement is in the loop\")\n",
    "    \n",
    "print (\"This statement is outside the loop\")\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=================\n",
      "0\n",
      "1\n",
      "B. exiting for loop without break\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "print ('=================')\n",
    "val = 0\n",
    "for i in range(0, random.randint(1, 10) ):\n",
    "    val += i\n",
    "    print (val)\n",
    "    if val>20:\n",
    "        print (' A. leaving the loop on break')\n",
    "        break # break out of loop\n",
    "else: # this else belongs to the for loop\n",
    "    print ('B. exiting for loop without break')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "DataMining \t is at index \t 0\n",
      "8 \t is at index \t 1\n",
      "23423423235 \t is at index \t 2\n",
      "2.546923764237654 \t is at index \t 3\n",
      "False \t is at index \t 4\n"
     ]
    }
   ],
   "source": [
    "# more for loop examples\n",
    "\n",
    "# you can also get the index using the enumerate example\n",
    "for index, val in enumerate(list_example):\n",
    "    print (str(val), '\\t is at index \\t', index)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "===============\n",
      "What is your name?  It is lancelot.\n",
      "What is your quest?  It is the holy grail.\n",
      "What is your favorite color?  It is blue.\n"
     ]
    }
   ],
   "source": [
    "print ('===============')\n",
    "# this is a classic example for zipping, provided by the official python tutorial\n",
    "# notice the references to Monty Python\n",
    "\n",
    "# say you have two lists of equal size, that you would like to \n",
    "# loop through without indexing, you can use the \"zip\" function\n",
    "questions = ['name', 'quest', 'favorite color']\n",
    "answers = ['lancelot', 'the holy grail', 'blue']\n",
    "for q, a in zip(questions, answers):\n",
    "    print ('What is your %s?  It is %s.' % (q, a))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "===============\n",
      "dict_keys(['bird', 'dog', 45, 'human'])\n",
      "bird => two and some wings\n",
      "dog => 4\n",
      "45 => a key that is not a string\n",
      "human => two\n",
      "===============\n",
      "bird => two and some wings\n",
      "dog => 4\n",
      "45 => a key that is not a string\n",
      "human => two\n",
      "===============\n",
      "human => two\n",
      "beast is not present.\n",
      "cat is not present.\n",
      "dog => 4\n",
      "45 => a key that is not a string\n"
     ]
    }
   ],
   "source": [
    "# Looping through dictionaries\n",
    "print ('===============')\n",
    "# Get all the keys.\n",
    "print (num_legs.keys())\n",
    "for k in num_legs.keys():\n",
    "    print (k, \"=>\", num_legs[k])\n",
    "\n",
    "print ('===============')\n",
    "# you can also use the iter_items function\n",
    "for k, v in num_legs.items():\n",
    "    print (k, \"=>\", v)\n",
    "\n",
    "print ('===============')\n",
    "# Test for presence of a key.\n",
    "for t in [ 'human', 'beast', 'cat', 'dog', 45 ]:\n",
    "    print (t,end=' ')\n",
    "    if t in num_legs:\n",
    "        print ('=>', num_legs[t])\n",
    "    else:\n",
    "        print ('is not present.')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561]\n",
      "['NAME', 'QUEST', 'FAVORITE COLOR']\n",
      "{0: 0, 1: 1, 2: 16, 3: 81, 4: 256, 5: 625, 6: 1296, 7: 2401, 8: 4096, 9: 6561}\n",
      "260\n"
     ]
    }
   ],
   "source": [
    "# list comprehensions and dictionary comprehensions\n",
    "\n",
    "# comprehensions are like shorthand for loops where each\n",
    "# pass through the loop saves the result in a list or dictionary\n",
    "\n",
    "# for example, imagine we want to take every element in a range to the fourth power\n",
    "times_four = [x**4 for x in range(10)]\n",
    "print (times_four)\n",
    "# this save the fourth power of the numbers 0 through 9\n",
    "# the result of each pass through the loop saves a value\n",
    "# in other languages this is also known as \"lambda functions\"\n",
    "\n",
    "# you can also call functions inside a comprehension, and take \n",
    "# advantage of the data type. For example, if each element is a string\n",
    "# we can use the string member methods\n",
    "questions = ['name', 'quest', 'favorite color']\n",
    "quest_upper = [x.upper() for x in questions]\n",
    "print (quest_upper)\n",
    "\n",
    "# you can also do comprehensions with dictionaries\n",
    "times_four = {x:x**4 for x in range(10)}\n",
    "# notice that the comprehension is wrapped in curly braces and the key for the value \n",
    "# is given inside the code itself, followed by a colon\n",
    "print (times_four)\n",
    "\n",
    "# you can also nest comprehensions inside each other, but this is not always good coding practice\n",
    "# especially if it makes the code less readable\n",
    "\n",
    "# Finally, all of the enumerate, zipping, and slicing we performed also applies to \n",
    "# list comprehensions\n",
    "x_array = [10, 20, 30]\n",
    "y_array = [7, 5, 3]\n",
    "# this prints the sum of the multiplication of the arrays\n",
    "print (sum(x*y for x,y in zip(x_array, y_array)) ) \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Stack Example:\n",
      "['LIFO', 0, 1, 2, 3, 4]\n",
      "=============\n",
      "4\n",
      "=============\n",
      "['LIFO', 0, 1, 2, 3]\n",
      "=============\n"
     ]
    }
   ],
   "source": [
    "#============================================\n",
    "# array as a stack\n",
    "print (\"\\nStack Example:\")\n",
    "list_example = []\n",
    "list_example.append('LIFO')\n",
    "\n",
    "for i in range(0, 5):\n",
    "    list_example.append(i)\n",
    "\n",
    "print (list_example)\n",
    "print (\"=============\")\n",
    "val = list_example.pop()\n",
    "print (val)\n",
    "print (\"=============\")\n",
    "print (list_example)\n",
    "print (\"=============\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Queue Example:\n",
      "deque([9, 8, 7, 6, 5, 'FIFO'])\n",
      "=============\n",
      "FIFO\n",
      "=============\n",
      "deque([9, 8, 7, 6, 5])\n",
      "=============\n",
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "9\n"
     ]
    }
   ],
   "source": [
    "#============================================\n",
    "# array as a queue\n",
    "print (\"\\nQueue Example:\")\n",
    "from collections import deque # this is an import, we will get back to that later\n",
    "# essentially this is a set of utility functions shipped with python\n",
    "\n",
    "q_example = deque()\n",
    "q_example.appendleft(\"FIFO\")\n",
    "for i in range(5, 10):\n",
    "    q_example.appendleft(i)\n",
    "\n",
    "print (q_example)\n",
    "print (\"=============\")\n",
    "val = q_example.pop()\n",
    "print (val)\n",
    "print (\"=============\")\n",
    "print (q_example)\n",
    "print (\"=============\")\n",
    "\n",
    "# pop and print each element\n",
    "while len(q_example) > 0:\n",
    "    print (q_example.pop())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Conditional Example:\n",
      "a is true\n",
      "b is false\n"
     ]
    }
   ],
   "source": [
    "#============================================\n",
    "# conditional example\n",
    "print (\"\\nConditional Example:\")\n",
    "\n",
    "a, b = True, False  # double assignment\n",
    "\n",
    "if a:\n",
    "    print (\"a is true\")\n",
    "elif a or b:\n",
    "    print (\"b is true\")\n",
    "else:\n",
    "    print (\"neither a or b are true\")\n",
    "\n",
    "# conditional assignment\n",
    "val = \"b is true\" if b else \"b is false\"\n",
    "print (val)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I. Everybody is a five!\n",
      "II. These are the same object!\n",
      "III. Wish we had the same objects...\n",
      "IV. Everybody is a five!\n",
      "V. Wish we had fives...\n",
      "VI. Got through nested conditional\n"
     ]
    }
   ],
   "source": [
    "# more on conditionals, \"is\" versus ==\n",
    "\n",
    "# I. the traditional == works as expected\n",
    "a=5\n",
    "b=5\n",
    "if a==b:\n",
    "    print (\"I. Everybody is a five!\")\n",
    "else:\n",
    "    print (\"I. Wish we had fives…\" )\n",
    "    \n",
    "# II. the \"is\" function is for object comparison, much like comparing pointers\n",
    "a=327676\n",
    "b=a\n",
    "if a is b:\n",
    "    print (\"II. These are the same object!\")\n",
    "else:\n",
    "    print (\"II. Wish we had the same objects...\" )\n",
    "    \n",
    "# III. while these have the same value, they are not the same memory\n",
    "a=327676\n",
    "b=327675+1\n",
    "if a is b:\n",
    "    print (\"III. These are the same object!\")\n",
    "else:\n",
    "    print (\"III. Wish we had the same objects...\" )\n",
    "\n",
    "# IV. you would expect this to say wish we had fives,\n",
    "# but small integers like this are cached so right now they do point to the same memory\n",
    "a=5\n",
    "b=4+1\n",
    "if a is b:\n",
    "    print (\"IV. Everybody is a five!\")\n",
    "else:\n",
    "    print (\"IV. Wish we had fives...\" )\n",
    "    \n",
    "# V. but if we change the memory, that caching gets released\n",
    "b = b*2.0\n",
    "b = b/2.0\n",
    "if a is b:\n",
    "    print (\"V. Everybody is a five!\")\n",
    "else:\n",
    "    print (\"V. Wish we had fives...\")\n",
    "    \n",
    "# you can also perform nested conditionals, like bounding\n",
    "if 5 < 8 < 6: # not true because 8 is not less than 6\n",
    "    print ('VI. How did we get here')\n",
    "elif 4 < 18 < 22:\n",
    "    print (\"VI. Got through nested conditional\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Pythonic\n",
    "Now that we have gone through a consierable number of examples and data types, we need to talk about what it means to write code in python that is \"pythonic\". In a nutshell, there are many ways to implement something in python. The \"best\" method is one that is readable, simple, and brief. \n",
    "\n",
    "There many different coding “styles”\n",
    "+ “best” styles get the distinction of “pythonic”\n",
    "    + ill formed definition\n",
    "    + changes as the language matures\n",
    "+ pythonic code is:\n",
    "    + simple and readable\n",
    "    + uses dynamic typing when possible\n",
    "    + uses underscores to separate names\n",
    "    + names of variables are distinctive\n",
    "+ …or to quote Tim Peters…, run the next cell\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The Zen of Python, by Tim Peters\n",
      "\n",
      "Beautiful is better than ugly.\n",
      "Explicit is better than implicit.\n",
      "Simple is better than complex.\n",
      "Complex is better than complicated.\n",
      "Flat is better than nested.\n",
      "Sparse is better than dense.\n",
      "Readability counts.\n",
      "Special cases aren't special enough to break the rules.\n",
      "Although practicality beats purity.\n",
      "Errors should never pass silently.\n",
      "Unless explicitly silenced.\n",
      "In the face of ambiguity, refuse the temptation to guess.\n",
      "There should be one-- and preferably only one --obvious way to do it.\n",
      "Although that way may not be obvious at first unless you're Dutch.\n",
      "Now is better than never.\n",
      "Although never is often better than *right* now.\n",
      "If the implementation is hard to explain, it's a bad idea.\n",
      "If the implementation is easy to explain, it may be a good idea.\n",
      "Namespaces are one honking great idea -- let's do more of those!\n"
     ]
    }
   ],
   "source": [
    "import this # the zen of python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pop Quiz!!!\n",
    "Which of these is more pythonic: You want to add the numbers between zero and N. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8128\n",
      "8128\n",
      "8128.0\n"
     ]
    }
   ],
   "source": [
    "N = 128\n",
    "\n",
    "sum_value = 0\n",
    "for i in range(N):\n",
    "    sum_value += i\n",
    "print (sum_value)\n",
    "\n",
    "# OR\n",
    "print (sum(range(N)))\n",
    "\n",
    "# OR\n",
    "print (N*(N-1)/2 )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Functions and Classes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Function Example:\n",
      "upper case\n",
      "data mining\n"
     ]
    }
   ],
   "source": [
    "#============================================\n",
    "print (\"\\nFunction Example:\")\n",
    "\n",
    "# create and call a function\n",
    "# the function can be defined almost anywhere in file, as long as it is defined before it gets used\n",
    "def make_strings_lowercase(str_input):\n",
    "    assert isinstance(str_input, str)  # test the type of input\n",
    "    return str_input.lower()\n",
    "\n",
    "# now we are back on the main execution\n",
    "print (make_strings_lowercase(\"UPPER CASE\"))\n",
    "print (make_strings_lowercase(\"Data Mining\"))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3, 4, 5]\n",
      "====================\n",
      "[1, 2, 3, 4, 5]\n",
      "[1, 2, 3, 4, 5]\n",
      "a cool X value\n",
      "[1, 2, 3, 4, 5]\n",
      "a cool X value\n",
      "a cool Y value\n",
      "====================\n",
      "(4, 1024)\n"
     ]
    }
   ],
   "source": [
    "# more functions examples\n",
    "def show_data(data):\n",
    "    # print the data\n",
    "    print (data)\n",
    "\n",
    "some_data = [1,2,3,4,5]\n",
    "show_data(some_data)\n",
    "\n",
    "# you can also define default values for the functions\n",
    "print ('====================')\n",
    "def show_data(data,x=None,y=None):\n",
    "    # print the data\n",
    "    print (data)\n",
    "    if x is not None:\n",
    "        print (x)\n",
    "    if y is not None:\n",
    "        print (y)\n",
    "\n",
    "some_data = [1,2,3,4,5]\n",
    "show_data(some_data);\n",
    "show_data(some_data,x='a cool X value')\n",
    "show_data(some_data,y='a cool Y value',x='a cool X value') \n",
    "\n",
    "# as well as have multiple return types in the function\n",
    "print ('====================')\n",
    "def get_square_and_tenth_power(x):\n",
    "    return x**2,x**10\n",
    "\n",
    "print (get_square_and_tenth_power(2) )\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name: Heart has 1 beats per second\n",
      "This is a long string meant to be so long that the memory for it is not cached by python\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "# This is a class that inherits from a generic object\n",
    "class BodyPart(object):\n",
    "    kind = \"This is a long string meant to be so long that the memory for it is not cached by python\"\n",
    "    # this is a class variable, shared across all instances\n",
    "    def __init__(self,name):\n",
    "        self.name = name # the name attribute is unique to each instance of the BodyPart class\n",
    "\n",
    "# now define a class that sub classes from the defined BodyPart CLass\n",
    "class Heart(BodyPart):\n",
    "    def __init__(self,rate=60,units=\"minute\"):\n",
    "        self.rate = rate\n",
    "        self.units= units\n",
    "        super(Heart,self).__init__(\"Heart\")\n",
    "\n",
    "    def __str__(self):\n",
    "        return \"name: \" + str(self.name) + \" has \" + str(self.rate) + \" beats per \" + self.units\n",
    "        \n",
    "\n",
    "my_heart = Heart(1,\"second\")\n",
    "print(my_heart)\n",
    "\n",
    "generic_part = BodyPart(\"Foot\")\n",
    "print (my_heart.kind)\n",
    "print (my_heart.kind is generic_part.kind) # true, these are the same memory location\n",
    "\n",
    "# take the following for example, these are not the same object\n",
    "a = \"This is a long string meant to be so long that the memory for it is not cached by python\"\n",
    "b = \"This is a long string meant to be so long that the memory for it is not cached by python\"\n",
    "print (a is b) # not the same memory location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 5\n",
      "\n",
      "Some value is out of range: list index out of range\n"
     ]
    }
   ],
   "source": [
    "# error handling and exceptions\n",
    "# Python exception handling.\n",
    "\n",
    "# example reissued from: http://sandbox.mc.edu/~bennet/python/code/exc_py.html\n",
    "\n",
    "# Choose two random integers.\n",
    "import random\n",
    "i = random.randrange(0, 8)\n",
    "j = random.randrange(-1, 6)\n",
    "print( i, j)\n",
    "\n",
    "# Get a nice little array, then try a bunch of dangerous stuff.\n",
    "some = [3, 10, 0, 8, 18];\n",
    "try:\n",
    "    # We try to execute this block.\n",
    "    den = some[j] / i\n",
    "    print (\"A:\", den)\n",
    "    frac = (i + j) / den\n",
    "    print (\"B:\", frac)\n",
    "    if frac < 2:\n",
    "        k = 3\n",
    "    else:\n",
    "        k = 'mike'\n",
    "    print (\"C:\", k)\n",
    "    print (\"D:\", some[k])\n",
    "# This is the catch block.\n",
    "except ZeroDivisionError:\n",
    "    print (\"\\nDivision by zero.\")\n",
    "except TypeError as inst:\n",
    "    # The detail provides extra information about the exception.\n",
    "    print (\"\\nSome type mismatch:\", inst)\n",
    "except IndexError as inst:\n",
    "    print (\"\\nSome value is out of range:\", inst)\n",
    "except:\n",
    "    # Except without an exception name catches any exception.\n",
    "    print (\"\\nSomething else went wrong.\")\n",
    "\n",
    "# An else attached to an except block is run if no exception occurrs.\n",
    "else:\n",
    "    print (\"\\nThat's odd, nothing went wrong.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Could not read file: [Errno 2] No such file or directory: 'some_file.txt'\n"
     ]
    }
   ],
   "source": [
    "# the with command and opening a file\n",
    "\n",
    "# the regular way of opening a file, lots of error checking\n",
    "try:\n",
    "    file = None\n",
    "    file = open(\"some_file.txt\")\n",
    "    data = file.read()\n",
    "except IOError as inst:\n",
    "    print (\"\\nCould not read file:\", inst)\n",
    "else:\n",
    "    print (\"Read successfully, file contents:\")\n",
    "    print (data)\n",
    "finally:\n",
    "    # this always gets called, close the file if its open\n",
    "    if file!= None and not file.closed:\n",
    "        file.close()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "FileNotFoundError",
     "evalue": "[Errno 2] No such file or directory: 'some_file.txt'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-77-fbe61a590b45>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0;31m# in that respect, the \"with\" statement is a protocol that the \"file class\" adopts\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"some_file.txt\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mfile\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      8\u001b[0m     \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfile\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      9\u001b[0m     \u001b[0mprint\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m\"Read successfully, file contents:\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'some_file.txt'"
     ]
    }
   ],
   "source": [
    "# the \"file\" class actually has a built in __init__ and __exit__\n",
    "# so we can really on their class implemntation to close the file propoerly\n",
    "# and handle any exceptions gracefully\n",
    "\n",
    "# in that respect, the \"with\" statement is a protocol that the \"file class\" adopts\n",
    "\n",
    "with open(\"some_file.txt\") as file:\n",
    "    data = file.read()\n",
    "    print (\"Read successfully, file contents:\")\n",
    "    print (data)\n",
    "\n",
    "# is the file closed? Let's check\n",
    "print (file.closed)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1. Just initialized body part with name Lungs\n",
      "2. Building up from \"with\" command\n",
      "3. Hi, my name is: Lungs\n",
      "4. Exit was called, no errors\n"
     ]
    }
   ],
   "source": [
    "# you can also define your own classes that adopt the \"with\" protocol,\n",
    "# if you are interested check out the example \n",
    "class BodyPart(object):\n",
    "    def __init__(self,name):\n",
    "        self.name = name\n",
    "        print ('1. Just initialized body part with name', name)\n",
    "        \n",
    "    def __enter__(self):\n",
    "        print ('2. Building up from \"with\" command' )\n",
    "        return self\n",
    "        \n",
    "    def __exit__(self, type, value, traceback):\n",
    "        if value is not None:\n",
    "            print ('4. An error occurred,', value)\n",
    "        else:\n",
    "            print ('4. Exit was called, no errors')\n",
    "            \n",
    "    def __str__(self):\n",
    "        # 5/0 # uncomment to raise an error\n",
    "        return '3. Hi, my name is: '+ self.name\n",
    "\n",
    "with BodyPart(\"Lungs\") as bp:\n",
    "    print(bp)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Importing Libraries\n",
    "Python shipd with many libraries already packaged. You simply import them using the \"import\" command. However, you can also install many third party libraries, of which there are many for data wrangling. In the next examples we will use some built in libraries, as well as ones that are third party.\n",
    "\n",
    "FOr installing the third party libraries, you will need to install a package mananger. There are three main ones that you may want to use on your system:\n",
    "+ Pip, https://pypi.python.org/pypi/pip\n",
    "+ Homebrew, http://brew.sh\n",
    "+ Macports, https://www.macports.org\n",
    "    \n",
    "I have had the best luck using pip (even on mac, after installing brew). But you will need to explore the options and decide which one is right for your system. If you are using windows, pip is the way to go. If you do not want the setup to affect other libraries installed on your system, consider setting up a virtual environment. http://docs.python-guide.org/en/latest/dev/virtualenvs/\n",
    "\n",
    "Now go our and install the Numpy and Matplotlib systems on your system! It might be as simple as:\n",
    "     > pip install numpy\n",
    "     > pip install matplotlib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.999874127674\n",
      "-1.22464679915e-16\n"
     ]
    }
   ],
   "source": [
    "# with the package installed, we can import the libraries and use them.\n",
    "\n",
    "# The numpy package is great for working with groups of numbers as matrices\n",
    "# and has many functionalities that are comparable to Matlab and Octave\n",
    "import numpy as np\n",
    "t = np.linspace(0, 1, 100)  # 100 equally spaced array of numbers from 0.0 to 1\n",
    "y = np.sin(2 * np.pi * t)  # take sine of the value\n",
    "\n",
    "print (np.max(y))\n",
    "print (np.median(y))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhcAAAFkCAYAAACThxm6AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzt3XmczuX+x/HXNdaSrSK0k4rqJ0urQtHq6ETrRGhBiIw9\nS1myk1SISErmlFTaTlpOixYqY6lT6bTotFFatAgx1++PzzhNkzHbfd/Xvbyfj8f9iHvu5T1f08x7\nru/1vS7nvUdEREQkUtJCBxAREZHkonIhIiIiEaVyISIiIhGlciEiIiIRpXIhIiIiEaVyISIiIhGl\nciEiIiIRpXIhIiIiEaVyISIiIhGlciEiIiIRFdVy4Zw73Tn3uHPuS+dctnPugkI8p4VzbqVzbqtz\n7kPnXKdoZhQREZHIivbIRQVgNdADKHATE+fcYcCTwAtAA2AaMMc5d1b0IoqIiEgkuVhtXOacywYu\n9N4/vofHTADO897/X677MoHK3vvzYxBTRERESije5lycDDyf576lwCkBsoiIiEgxlA4dII8awMY8\n920EKjnnynnvt+V9gnNuP+AcYD2wNeoJRUREkkd54DBgqff+u0i9aLyVi+I4B3ggdAgREZEE1h5Y\nGKkXi7dysQE4IM99BwA/7W7UIsd6gAULFlCvXr0oRpPcMjIymDp1aoGP8x7+8x945RVYtgzefdfu\nr1oV6tSB2rXtdsABUK7cH7cyZeCnn2DTJvj2W/vvl1/CmjX2Z4DDDoMTT4Tzz4djjwXnovf5xoPC\nHnOJHB3z2NMxj63333+fDh06QM7P0kiJt3LxBnBenvvOzrk/P1sB6tWrR6NGjaKVS/KoXLnyHo/3\npk1w990waxZ89hlUrAjnnAP9+9t/a9Qo3vt6b6/32mvw6qvwxBPw0ENQty506GC32rWL+UnFuYKO\nuUSejnns6ZgHE9FpBdFe56KCc66Bc+74nLtq5/z94JyPj3POzc/1lLtyHjPBOXeUc64HcDFwazRz\nSuSsXg3XXAMHHQSjRkHLlvDcc1Y2Fi2CTp2KXyzARicOOwzat4eZM61oPP88nHoqTJpkoyHnnw/L\nl0fsUxIRkSKK9tUiTYBVwEpsnYspQBYwMufjNYCDdz3Ye78eaA20wtbHyACu8d7nvYJE4szq1XDW\nWdCwITz7LIwYAZ9/DnPnQqtWULZsdN63VCkrMPfeCxs2wPz5sH49nHIKnH22jXCIiEhsRbVceO9f\n9t6nee9L5bldnfPxq7z3Z+Z5zive+8be+72893W99/dHM6OUzJdfwlVXQaNG8MUX8OCD8OmnMHgw\n7L9/bLNUqAAdO9q8jocegq+/htNOs3LzzjuxzSIiksribZ0LSRBt26Zz00021+HJJ+HOO2HtWrj0\nUigdeCZPWhpccolN/ly8GL76ykZUBg6EX38Nm60k0tPTQ0dIOTrmsadjnhxitkJntDjnGgErV65c\nqUlAMfLaazZ34osvICPDRikqVw6dKn/bt8PkyTB6tF2Vcued8Le/hU4lIhJeVlYWjRs3Bmjsvc+K\n1Otq5EIKbds2KxLNmkH16naqYdy4+C4WYPM9hgyx0yVHHQVt2tgIyw8/hE4mIpKcVC6kUFavhhNO\ngFtvhTFjbM2KunVDpyqaOnXgmWcgM9OuMGnYEFasCJ1KRCT5qFxIgWbPtsWqnIO33rLRi1KlQqcq\nHufg8sth1SqoWdMmfN56q62fISIikaFyIfnavh26d4du3aBLF3jzTWjQIHSqyDj0UFs1tE8f6NcP\n/v53+P770KlERJKDyoXs1saNtn7E3Lm20ub06bYsdzIpU8YW3nriCZuketJJ8NFHoVOJiCQ+lQv5\ni5UroUkT2xPkpZfg2mtDJ4quv/3NTveUKgUnnwyvvx46kYhIYlO5kD959lm7GqRmTSsZp54aOlFs\n1K5tpeKYY+DMM22pchERKR6VC/mfhx+23+JbtLARiwMPDJ0otvbd18pVu3Z2qerkyZroKSJSHPG2\nK6oEMncudO1qV1Lce6/NR0hF5crBggVw+OEwYIBtuDZuXPJv5y4iEkkqF8LkyfaDtEcPuOMOWz47\nlaWl2Voe1arZCqQ7d8LEiSoYIiKFpXKR4kaOtB1Mhw2zLdL1A/QPffpY0bjhBisYU6bo+IiIFIbK\nRQqbONGKxbhxtjCW/FXv3nYVyfXXQ3Y2TJ2qgiEiUhCVixQ1fToMGgTDh6tYFKRnTysY3btbwZg2\nTQVDRGRPVC5S0Lx59pt43752WkQKdt11doqkWzeoWlXHTURkT1QuUsyDD9qiWN262URO/QZeeF27\n2k6qgwfb1u09eoROJCISn1QuUsjSpdChA7RvDzNmqFgUx8CBsGGDjfxUrw4XXxw6kYhI/FG5SBFr\n18Ill8DZZ8M99+hy0+Jyzq4a2bjRStr++9uiYyIi8gf9iEkBX30FrVtDnTp2WqS0KmWJpKXZQmPN\nmtluqqtXh04kIhJfVC6S3C+/2JLe3sOTT8I++4ROlBzKloVHHoG6de34fv116EQiIvFD5SKJ7dwJ\n6em2u+lTT6XeXiHRVrGibdfuPbRtC1u3hk4kIhIfVC6SWEYG/POf8NBD0KBB6DTJqWZNWLIE1qyx\nq0m00ZmIiMpF0po3z/YJuf12OO+80GmSW5MmNkn2/vvt8l4RkVSnqX1JaOVKW03ymmvsvxJ96enw\n7ru26mn9+jaBVkQkVWnkIsls2gTt2sFxx8Gdd2oti1gaPRouuMCKxvvvh04jIhKOykUS2bEDLr8c\ntmyBxYuhfPnQiVJLWpqdGjn4YFtc69dfQycSEQlD5SKJDBsGL75oa1kcckjoNKmpYkV4+GFYv95O\nSWmCp4ikIpWLJPHIIzBhgt3OPDN0mtRWrx7MmmWjGPfcEzqNiEjsqVwkgfXr4eqr4aKLoF+/0GkE\nbA+Xrl1tD5K1a0OnERGJLZWLBPf77zaBsEoVmDNHEzjjybRpcPTRNv/ip59CpxERiR2ViwQ3YgS8\n9RZkZlrBkPhRvjwsWmS7qHbpovkXIpI6VC4S2L/+BePG2SWQp5wSOo3szhFH2LyLhx6yhc1ERFKB\nykWC+vZbO69/xhkwcGDoNLInF19sC5r17g0ffxw6jYhI9KlcJCDvoXNnm29x//1QqlToRFKQ226D\nGjWsEO7YETqNiEh0qVwkoOnT4emnYf58qFUrdBopjH32gQULbH7M2LGh04iIRJfKRYL5z3/sNEiP\nHnD++aHTSFGcfLItdDZqFCxfHjqNiEj0qFwkkJ07oVMnG62YODF0GimOoUNtF9UOHeCXX0KnERGJ\nDpWLBDJ5sv3GO38+VKgQOo0UR5kyNk9mwwbIyAidRkQkOlQuEsQ778BNN0H//tC0aeg0UhJ168Kt\nt9qiZ88+GzqNiEjkqVwkgO3b7XRI3bp2vl4SX5cu0LKl/ffnn0OnERGJLJWLBDBmjI1czJ+vbdST\nhXM2cvHdd1qnRESSj8pFnFu92srF0KHQuHHoNBJJhx1mu9jedZettioikixULuLYjh1w7bVQvz4M\nGRI6jURD9+7QvLn9O+vqERFJFioXcWzaNMjKsuHzsmVDp5FoSEuzf98NG1QgRSR5qFzEqU8+geHD\n4YYb4MQTQ6eRaDriCFu18447YNmy0GlEREpO5SIOeQ/dukH16rbjqSS/Xr1sZ9uuXWHbttBpRERK\nRuUiDt13Hzz/vE3022ef0GkkFkqVglmz4KOPYNKk0GlEREpG5SLObNxoKzd26ADnnhs6jcTSccdB\nv35wyy22h4yISKJSuYgzGRn2W+zUqaGTSAg33QQ1a9rGdN6HTiMiUjwqF3HkhRcgM9P2ENl//9Bp\nJIS994YZM+y02MKFodOIiBSPykWc2LYNevaE00+Hjh1Dp5GQzjsPLr0U+vaF778PnUZEpOhULuLE\nlCk2mW/GDFsaWlLbbbfB1q0weHDoJCIiRadyEQfWr7dJfBkZcOyxodNIPKhZE8aNg7vvhjfeCJ1G\nRKRoVC7iwA03wL77ws03h04i8aRbN2jUCK6/HnbuDJ1GRKTwVC4Ce+IJePxxGwbXmhaSW6lScOed\nfywBLyKSKFQuAtqyBXr3hnPOgYsuCp1G4tEpp0DnzrbvyHffhU4jIlI4KhcBTZgAX31le0poEqfk\nZ/x42yF32LDQSURECkflIpDPPoOJE6F/f6hbN3QaiWcHHACjRtny4FlZodOIiBRM5SKQAQOgalW4\n8cbQSSQR9OgB9evb5M7s7NBpRET2TOUigJdegkWL7LSIJnFKYZQpY6fP3ngDFiwInUZEZM9ULmJs\n50679PTkk6F9+9BpJJGccQZcdhkMHAg//xw6jYhI/lQuYuzuu2HtWpg2DdJ09KWIJk6EzZttkqeI\nSLzSj7cY+uEHm/HfqROceGLoNJKIDjnEJgFPmWIru4qIxCOVixgaMcI2KBs3LnQSSWSDBtmKrtp3\nRETilcpFjLz/PkyfDkOH2r4RIsW1zz4wZgw8+CC8/nroNCIifxX1cuGc6+mc+9Q595tzbrlz7oQ9\nPLa5cy47z22nc656tHNG26BBcPDB0KdP6CSSDDp1goYN7etJl6aKSLyJarlwzl0GTAFuBhoCa4Cl\nzrn99/A0D9QFauTcanrvv4lmzmh78UXbQ2T8eChfPnQaSQZpabYfzVtvwcKFodOIiPxZtEcuMoBZ\n3vv7vPcfANcBW4CrC3jet977b3bdopwxqrKzoV8/OOkkuPTS0GkkmTRrBu3a2dyLX38NnUZE5A9R\nKxfOuTJAY+CFXfd57z3wPHDKnp4KrHbOfeWce9Y5d2q0MsbCggWwapXN7tf+IRJpEyfCt9/a15eI\nSLyI5sjF/kApYGOe+zdipzt252ugG3AR0A74HHjJOXd8tEJG05YtNoHzoougadPQaSQZ1akDvXpZ\nydiY9/80EZFA4upqEe/9h977u733q7z3y7331wCvY6dXEs5tt9k3fC14JNE0ZIgtDz5yZOgkIiKm\ndBRfexOwEzggz/0HABuK8DpvAgX+3p+RkUHlypX/dF96ejrp6elFeKvI2bjR1rPo2ROOOCJIBEkR\n++5rI2SDB9vS8kcdFTqRiMSjzMxMMjMz/3Tf5s2bo/JezqZBRIdzbjmwwnt/Q87fHfBf4Hbv/aRC\nvsazwE/e+4vz+XgjYOXKlStp1KhRhJKXXPfu8I9/wMcf2zd/kWjautVKRePG8MgjodOISKLIysqi\ncePGAI2991mRet1ojlwA3Arc65xbiY1AZAB7A/cCOOfGAbW8951y/n4D8Cnwb6A80AU4Azgryjkj\nat0620NkwgQVC4mN8uVtYa0rr4TXXtMcHxEJK6pzLrz3DwH9gVHAKuD/gHO899/mPKQGcHCup5TF\n1sVYC7wEHAe09N6/FM2ckTZsGNSqZadERGLliivg+ONhwACI4oCkiEiBoj1ygfd+BjAjn49dlefv\nk4BCnS6JVytWwMMPw733asEsia20NJg0Cc46Cx591NbAEBEJIa6uFkl03tukumOPhQ4dQqeRVNSq\nFZxzjn0d/v576DQikqpULiJo6VJ46SW7SqRUqdBpJFVNmAAffQRz5oROIiKpSuUiQrKz7bfF00+H\n1q1Dp5FU1qCBzb8YPdoWchMRiTWViwjJzIQ1a+y3Ri3zLaGNHGnLgt9xR+gkIpKKVC4iYNs2u0Lk\nwgvhlD3tmiISI3XqQNeutjrsDz+ETiMiqUblIgJmzYL//hfGjg2dROQPw4ZZ8Z2U0NdfiUgiUrko\noV9+scWLOnWCevVCpxH5Q82a0KcPTJsGG4qy4L6ISAmpXJTQ7bfbsPPNN4dOIvJXAwZA2bJwyy2h\nk4hIKlG5KIEff7Qh527d4NBDQ6cR+auqVe0qplmz4JNPQqcRkVShclECkyfbOe2hQ0MnEclfr15Q\nrZpG10QkdlQuiumbb+C226B3b6hRI3QakfztvTcMHw4PPAD//nfoNCKSClQuimnXKpwDB4ZOIlKw\na66xU3cavRCRWFC5KIbPP4eZM6F/f22pLomhbFkrFosXw6pVodOISLJTuSiG0aOhYkW7zE8kUXTo\nAEceCTfdFDqJiCQ7lYsi+ugjuOceuPFGKxgiiaJ0aRgxAp58EpYvD51GRJKZykURjR4N1atD9+6h\nk4gU3WWXwTHHaPRCRKJL5aII1q2DBQtgyBDYa6/QaUSKLi0NRo2C556Dl18OnUZEkpXKRRGMGgW1\nasG114ZOIlJ8bdtCw4Z2ear3odOISDJSuSik996zbdWHDYPy5UOnESk+5+z03rJl8PzzodOISDJS\nuSikESPgkEPgqqtCJxEpufPPh5NP1uiFiESHykUhrF0LixbZN+KyZUOnESk552DkSFixAp55JnQa\nEUk2KheFMGIE1K4NHTuGTiISOWedBaeeaotrafRCRCJJ5aIAWVnw6KN26V6ZMqHTiETOrtGLt96C\nf/4zdBoRSSYqFwUYMcJWNWzfPnQSkchr2RKaNtXohYhElsrFHqxcCU88YaMWpUuHTiMSebtGL95+\nG556KnQaEUkWKhd7MHKkjVpcfnnoJCLRc+aZcPrpNkqn0QsRiQSVi3xkZdmoxfDhtrW6SLJyzorF\nypW274iISEmpXORj1CioW1ejFpIazjgDmjXT6IWIRIbKxW6sWgVLltioheZaSCrYNfdi14idiEhJ\nqFzsxqhRcMQRkJ4eOolI7LRoAc2b29e/Ri9EpCRULvJYvRoee0yjFpKabrrJ5l48/XToJCKSyFQu\n8tg1anHFFaGTiMTeGWfYuhcavRCRklC5yGXNGluNc+hQjVpIanLOFtR680149tnQaUQkUalc5DJ6\ntO0h0qFD6CQi4bRqZTumjhyp0QsRKR6VixzvvguLF2vUQsQ5m3vxxhvwwguh04hIIlK5yDFmDBx6\nKFx5ZegkIuGdey6ccIJGL0SkeFQugHXr4MEH4cYbtfOpCPwxevHqq/Dyy6HTiEiiUbkAxo6FAw+E\nzp1DJxGJH61bQ6NGNnohIlIUKV8uPv4YHngABg6EcuVCpxGJH87Zei8vvWQjGCIihZXy5WLcOKhW\nDa69NnQSkfhzwQVw3HF2JZWISGGldLn47DOYPx8GDIC99gqdRiT+pKXBsGG25sWbb4ZOIyKJIqXL\nxfjxUKUKdOsWOolI/LroIjjqKLjlltBJRCRRpGy5+PJLuOce6N8fKlQInUYkfpUqZeu/PPGE7b0j\nIlKQlC0XkyZZqejRI3QSkfiXng6HH27rwYiIFCQly8XGjTB7NvTpAxUrhk4jEv9Kl7Z1YBYvhvfe\nC51GROJdSpaLqVPtm2WvXqGTiCSOTp1sPZixY0MnEZF4l3Ll4vvvYfp06NkTqlYNnUYkcZQtC4MG\nQWYmfPRR6DQiEs9Srlzcfjvs3AkZGaGTiCSea66B6tVtfRgRkfykVLn46SeYNs0uPa1ePXQakcSz\n1152hdV998F//xs6jYjEq5QqFzNnwpYt9s1RRIqnWzeoVAkmTgydRETiVcqUiy1bYMoUuOoqm5Qm\nIsWzzz52pdWcObBhQ+g0IhKPUqZc3H23TeYcNCh0EpHE16uXbfR3662hk4hIPEqJcrFtmw3hduhg\nCwGJSMlUqWJXXM2YAd99FzqNiMSblCgX8+fD11/D4MGhk4gkj4wMyM62K7BERHJL+nKxYwdMmAAX\nXwxHHx06jUjyqFYNuna1cvHTT6HTiEg8Sfpy8Y9/wCefwJAhoZOIJJ/+/W2y9MyZoZOISDxJ6nKR\nnW2L/bRuDccfHzqNSPI56CDo3NmuxNqyJXQaEYkXSV0uHnvMNlnSqIVI9AwaZFdizZkTOomIxIuk\nLRfe2/bQLVrAqaeGTiOSvGrXti3ZJ02C7dtDpxGReJC05eLZZyErC4YODZ1EJPndeCN88QXcf3/o\nJCISD5K2XIwZAyeeCC1bhk4ikvzq14e2bWH8eNsYUERSW1KWi2XL7DZkCDgXOo1IahgyxLZiX7Qo\ndBIRCS0py8WYMXDssdCmTegkIqmjSRM4+2wYO9bmPIlI6kq6crFyJSxdar9FpSXdZycS34YOhXfe\ngaeeCp1EREJKuh+/48ZBnTpwySWhk4iknmbN4LTTbPRQoxciqSupysX778Mjj9geIqVLh04jkpqG\nDIHly+Gll0InEZFQkqpcjB8PtWrBlVeGTiKSus49Fxo2tNELEUlNUS8XzrmezrlPnXO/OeeWO+dO\nKODxLZxzK51zW51zHzrnOhXmfb76Ch54wPY6KFcuMtlFpOics9GLF16AFStCpxGREKJaLpxzlwFT\ngJuBhsAaYKlzbv98Hn8Y8CTwAtAAmAbMcc6dVdB73XcfVK0KXbpEJruIFF+7drYL8bhxoZOISAjR\nHrnIAGZ57+/z3n8AXAdsAa7O5/HdgU+89wO99+u899OBh3NeZ48eewz69IEKFSIVXUSKKy3N5j4t\nWWJXj4hIaolauXDOlQEaY6MQAHjvPfA8cEo+Tzs55+O5Ld3D4/+nTBno2bN4WUUk8q64Ag491OZC\niUhqiebIxf5AKWBjnvs3AjXyeU6NfB5fyTm3x5kUl14KVaoUJ6aIREOZMjBwIPzjH/Dxx6HTiMju\nbN4cnddNmgs2P/gggwsuqPyn+9LT00lPTw+USESuugpGjYIJE2D27NBpRFJbZmYmmZmZf7pvzZro\ntAvno7TSTc5pkS3ARd77x3Pdfy9Q2XvfdjfPeRlY6b3vm+u+zsBU733VfN6nEbBy5cqVNGrUKLKf\nhIiU2MSJMGwYfPopHHhg6DQissvPP8OBB2bx88+NARp777Mi9dpROy3ivf8dWAn8b19S55zL+fvr\n+TztjdyPz3F2zv0ikoCuu84mWk+ZEjqJiOQ2ezZs2RKd14721SK3Al2ccx2dc0cDdwF7A/cCOOfG\nOefm53r8XUBt59wE59xRzrkewMU5ryMiCahSJejVC2bNgk2bQqcREYCtW2HyZGjdOjqvH9Vy4b1/\nCOgPjAJWAf8HnOO9/zbnITWAg3M9fj3QGmgFrMYuQb3Ge5/3ChIRSSA33GCLa02bFjqJiADcey9s\n3AidO0fn9aM+odN7PwOYkc/HrtrNfa9gl7CKSJLYbz/o1g3uuAMGDLDRDBEJY8cOm2R9ySV2uXg0\nJNXeIiISv/r1g99+gxm7/VVDRGLlH/+A9ettmf5oUbkQkZioVcsuTb311uhNIhORPcvOtmX5W7eG\nBg2i9z4qFyISMwMHwvffw9y5oZOIpKYlS+C992Do0Oi+j8qFiMRM7dqQng6TJsH27aHTiKQW72Hs\nWGjRAk4pcFONklG5EJGYGjwYPv8cFiwInUQktTz3HLz9dnTnWuyiciEiMXXMMdC2rW1otnNn6DQi\nqWPMGDjhBGjVKvrvpXIhIjE3ZAj85z+weHHoJCKp4dVX4ZVXbK6Fc9F/P5ULEYm5Jk3g7LPt/G+U\ntjcSkVzGjLFRwzZtYvN+KhciEsSQIbBmDTz1VOgkIsktKwueecb+n0uL0U99lQsRCaJZM2ja1H6j\n0uiFSPSMHQt16sCll8buPVUuRCQI5+z87/Ll8OKLodOIJKf334dHHoFBg6B01Df8+IPKhYgEc+65\n0KiRjV6ISOSNG2er43bsGNv3VbkQkWCcs/PA//qXjWCISOR8+iksXGibBZYrF9v3VrkQkaDatoV6\n9TR6IRJpEydC1arQpUvs31vlQkSCSkuDG2+EJ5+E1atDpxFJDl9+CffcAxkZsPfesX9/lQsRCS49\nHQ4/3Ga1i0jJTZlipeL668O8v8qFiARXurTtOfLww/DBB6HTiCS2b7+Fu+6C3r2hUqUwGVQuRCQu\ndOpks9rHjw+dRCSxTZ1qpxt79w6XQeVCROJCuXLQv7/tlvrpp6HTiCSmH36AO++EHj1gv/3C5VC5\nEJG40bUr7LsvTJgQOolIYrrjDvj9d+jbN2wOlQsRiRt7723fFOfNgy++CJ1GJLH8/DNMm2aXntao\nETaLyoWIxJUePaBCBZg0KXQSkcRy111WMAYMCJ1E5UJE4kylSnDDDTB7NmzcGDqNSGL47TeYPBk6\nd4aDDw6dRuVCROJQ795Qpoxdqy8iBZszBzZtsg3K4oHKhYjEnapVbfGfGTPgu+9CpxGJb9u22STo\nK66wrdXjgcqFiMSljAzwHm67LXQSkfg2bx589RUMHRo6yR9ULkQkLlWrBt27w+23w48/hk4jEp9+\n/90Wnrv0Ujj66NBp/qByISJxq18/G/K9887QSUTi0/33w2efwbBhoZP8mcqFiMStmjXtmv2pU+0S\nOxH5w44dMGYMtGsHxx4bOs2fqVyISFwbONCKxYwZoZOIxJfMTPjkk/gbtQCVCxGJcwcfDNdcY9fw\n//pr6DQi8WHnThu1aNMGGjYMneavVC5EJO4NHmyTOmfODJ1EJD4sWgTr1sHw4aGT7J7KhYjEvUMP\ntZUHJ02CLVtCpxEJKzsbbrkFzjkHTjghdJrdU7kQkYQwZIgtqDV7dugkImE9+ij8+9/xO2oBKhci\nkiAOPxw6drSVCH/7LXQakTCys2HkSGjVCpo2DZ0mfyoXIpIwhgyBb7+1fRREUtFjj8E778DNN4dO\nsmcqFyKSMI44Atq3txUJt24NnUYktrKzYdQoaNkSTjstdJo9U7kQkYQyZAhs2AD33BM6iUhsLVkC\na9bE/6gFqFyISII56ihIT4dx42xpcJFU4L2NWpxxBpx+eug0BVO5EJGEM3y47QI5d27oJCKxsWQJ\nrF6dGKMWoHIhIgnoqKPgiitg7FjNvZDk571dIdKiBTRvHjpN4ahciEhCGj4cvv5aoxeS/B5/PLFG\nLUDlQkQS1JFH2pUjGr2QZLZr1KJ5cxu5SBQqFyKSsIYNsytH7r47dBKR6FiyBFatghEjQicpGpUL\nEUlYRx4JHTrYlSNatVOSTXa2nQo588zEGrUAlQsRSXDDh8M332j0QpLPI4/A2rV2WiTRqFyISEI7\n4giNXkjy2bnTRi3OPjv+V+PcHZULEUl4w4fbniN33RU6iUhkLFoE772XmKMWoHIhIkmgTh3o3Nn2\nHPnll9BpREpm506bwHn++XDyyaHTFI/KhYgkheHD4Ycf4M47QycRKZnMTFi3LnFHLUDlQkSSxKGH\nQpcuMHFSPaBPAAAV0klEQVQibN4cOo1I8ezYYaXiggugSZPQaYpP5UJEksbQoTapc+rU0ElEimfB\nAvjoo8Rb1yIvlQsRSRq1akGPHlYuvvsudBqRotm+3UYt2rWDhg1DpykZlQsRSSqDBtmEuMmTQycR\nKZo5c+Czz2D06NBJSk7lQkSSSvXq0Ls33H47bNwYOo1I4WzZYqXiyiuhfv3QaUpO5UJEkk7//lC6\ntF2aKpIIpk+HTZsSa+fTPVG5EJGks+++0LcvzJwJn38eOo3Inm3ebEW4SxeoXTt0mshQuRCRpJSR\nAfvsA6NGhU4ismdTp9ppkWHDQieJHJULEUlKlSrZpanz5tmCRCLxaNMmmDIFrr/ernZKFioXIpK0\nune3b9jDh4dOIrJ7EyaAc3aVUzJRuRCRpFW+vC1GtGgRZGWFTiPyZ199ZcvV9+0L++8fOk1kqVyI\nSFLr2BGOPhqGDAmdROTPRo6EChVsflCyUbkQkaRWujTccgssXQovvRQ6jYhZtw7mzrV5QZUrh04T\neSoXIpL02rWzTaBuvBG8D51GxErFQQfZcvXJSOVCRJKeczBuHCxfDk88ETqNpLoVK2DxYrtMuly5\n0GmiQ+VCRFJCq1Zw5pk2erFjR+g0kqq8tytDjjsO2rcPnSZ6VC5EJGVMmADvvQfz54dOIqnqmWfg\n5ZdtJK1UqdBpoidq5cI5V9U594BzbrNz7gfn3BznXIUCnjPPOZed5/Z0tDKKSGpp0gTS0+Gmm2xF\nRJFYys6GwYOhWTM4//zQaaIrmiMXC4F6QEugNdAMmFWI5/0TOACokXNLj1ZAEUk9Y8bAt9/CbbeF\nTiKpZuFCWLv2j4WzkllUyoVz7mjgHOAa7/3b3vvXgV7A5c65GgU8fZv3/lvv/Tc5t83RyCgiqenw\nw22p5fHjrWSIxMLWrbZSbNu2cPLJodNEX7RGLk4BfvDer8p13/OAB04q4LktnHMbnXMfOOdmOOf2\njVJGEUlRQ4dCWhqMHh06iaSKO++0HXrHjg2dJDaiVS5qAN/kvsN7vxP4Pudj+fkn0BE4ExgINAee\ndi7ZB5BEJJb228+uGpk5Ez76KHQaSXabNtlCbtddZ6vFpoLSRXmwc24csKftVTw2z6JYvPcP5frr\nv51z7wAfAy2AF/f03IyMDCrnWeYsPT2d9HRN2RCRv+rd236bHDIEHnqo4MeLFNfo0XYJ6s03h82R\nmZlJZmbmn+7bvDk6Mw+cL8Jydc65/YD9CnjYJ8CVwGTv/f8e65wrBWwFLvbeLynCe34DDPXe353P\nxxsBK1euXEmjRo0K+7IiIsyfD507wxtvpMZ5cIm9Dz+EY46xkYt43Pk0KyuLxo0bAzT23kdse78i\njVx4778Dvivocc65N4AqzrmGueZdtAQcsKKw7+ecOwgrM18XJaeISGF06ABTp9qulK+9lvwz+CX2\nBg+GWrXghhtCJ4mtqMy58N5/ACwF7nbOneCcawrcAWR67zfselzOpM2/5/y5gnNuonPuJOfcoc65\nlsBjwIc5ryUiElGlSsGtt9rIxYMPhk4jyWbZMnj0UVswq3z50GliK5rrXFwBfIBdJfIk8ArQLc9j\n6gK7JkrsBP4PWAKsA+4G3gKaee9/j2JOEUlhZ54Jf/+7DVn/9lvoNJIssrOhXz9buO3yy0Onib0i\nnRYpCu/9j0CHAh5TKteftwLnRiuPiEh+Jk2y8+JTp9oET5GSevBBeOstW+o7LQU32kjBT1lE5M/q\n1rWFtcaOha81w0tKaMsWGwm78EJb6jsVqVyIiGCrJ5YvD8OGhU4iiW7iRNi4ESZPDp0kHJULERGg\nalUYMQLmzYNVqwp8uMhu/fe/tndI375Qp07oNOGoXIiI5OjWzVZQzMiwRY9EimrAACuqqT53R+VC\nRCRHmTJ2aerLL8PixaHTSKJ55RVb7XX8eKhYMXSasFQuRERyOfdcaNPGhrV//TV0GkkUO3fakvIn\nnWSLs6U6lQsRkTymToVvvrHFj0QKY+5cWLMGpk1LzUtP89IhEBHJo04dGDjQ1r/QrqlSkB9/hKFD\noWNHG7kQlQsRkd0aPBhq1IA+fUInkXg3fDhs3aqRrtxULkREdmPvvW1y51NPwZNPhk4j8SorC2bM\ngJEjbYMyMSoXIiL5aNcOWrWy0YutW0OnkXiTnQ09ekD9+tCrV+g08UXlQkQkH87B7bfDZ5+l9mqL\nsntz58KKFTBzpl3GLH9QuRAR2YN69WzkYswY+OST0GkkXmzaZPNyOneG004LnSb+qFyIiBTg5puh\nWjUbAtfKnQJWLLKzbalv+SuVCxGRAuyzD0yfDkuX2gqMktpef91OiYwbB9Wrh04Tn1QuREQKoU0b\nm+DZp4+tayCpaccOG8Fq0gS6dAmdJn6pXIiIFNK0afDLL9qUKpXdeiu8845N4ixVKnSa+KVyISJS\nSAcdZBM777oLli8PnUZi7aOPbP5NRoaNXEj+VC5ERIqgZ09o1Mi2Z//999BpJFa8h65doWZNWzBL\n9kzlQkSkCEqVglmz4N13bYhcUsO8efDii/ZvX6FC6DTxT+VCRKSIGje2iZ033wwffBA6jUTbhg3Q\nrx906gRnnRU6TWJQuRARKYbRo+Hgg+Hqq2HnztBpJJp697YVOKdMCZ0kcahciIgUw957wz332MTO\nO+4InUaiZckSWLTIloHfb7/QaRKHyoWISDGdfjpcf71dmvrRR6HTSKR9/z107w6tW8Nll4VOk1hU\nLkRESmDcOKhRA665xpaDluTRqxf89ptN4nQudJrEonIhIlICFSrYUtCvvGILK0lyePhhWLgQ7rwT\nDjwwdJrEo3IhIlJCZ5wB110HgwZp59RksHGj/XtedBFccUXoNIlJ5UJEJAImTrRNrDp2tP0nJDHt\nWiwrLc1GonQ6pHhULkREIqBiRbj/fnjjDRg/PnQaKa7774fHH4fZs6FatdBpEpfKhYhIhDRtaleO\njBgBb74ZOo0U1eef25oWV14JF14YOk1iU7kQEYmgm26Chg2hQwf49dfQaaSwdu60UrHPPrb7rZSM\nyoWISASVKQMPPABffgl9+4ZOI4U1diwsW2b/dlWrhk6T+FQuREQi7MgjbVOz2bPt/L3Et1dftVNZ\nw4ZB8+ah0yQHlQsRkSjo2hX+9jdbXOuLL0Knkfz88INdbnrqqTB8eOg0yUPlQkQkCpyzvUfKlYP0\ndPj999CJJC/v4dpr4Zdf7HRI6dKhEyUPlQsRkSipVg0efNAuTx02LHQayWv2bHjkEZgzBw45JHSa\n5KJyISISRU2b2roXEyfCE0+ETiO7rFkDffrYSpzt2oVOk3xULkREoqxfP2jTBjp1gvXrQ6eR77+H\ntm2hXj2beCuRp3IhIhJlzsH8+VC5Mlx6KWzfHjpR6tq5E9q3h82b7ZTIXnuFTpScVC5ERGKgalV4\n6CFYvRoyMkKnSV0jR8LSpZCZCYcdFjpN8lK5EBGJkRNOgDvugBkzbDKhxNbjj8Po0TBmDJx9dug0\nyU0X3oiIxFC3brB2LfTsCUcfDc2ahU6UGj780Jb3btsWBg8OnSb5aeRCRCTGbrsNTj8dLrpIEzxj\n4ccfbSOymjXh3nu1jXosqFyIiMRYmTKwaBFUqgQXXAA//xw6UfLavh0uvhg2bIAlS+yYS/SpXIiI\nBLDffjYHYP166NgRsrNDJ0o+3ts6Fq+8Ao8+CkcdFTpR6lC5EBEJ5JhjYOFC+416wIDQaZLP2LEw\nb54tw64NyWJL5UJEJKC//Q1uv90Wc5o8OXSa5JGZaUuujxwJHTqETpN6dLWIiEhg118PGzfa6EX1\n6naaRIpv2TLo3NmOo3Y6DUPlQkQkDowaZZMOr74a9t8fzj8/dKLE9PbbNhrUtCncfbeuDAlFp0VE\nROKAczBzpv1gvOQSWL48dKLE8847cM45UL++zWMpWzZ0otSlciEiEidKl7a5Ao0aQevWsGpV6ESJ\n48MP4ayzbOv0f/4TKlYMnSi1qVyIiMSRvfayrdnr1IGWLWHlytCJ4t/69Xas9tsPnn0WqlQJnUhU\nLkRE4kyVKvZD8sgjoVUreOut0Ini1+efW7EoVw6eew6qVQudSEDlQkQkLlWpYrt3Hn20DfevWBE6\nUfxZt84mbmZnwwsvQK1aoRPJLioXIiJxqnJlKxjHHGO7eL7xRuhE8SMry/ZnqVgRXn0VDj00dCLJ\nTeVCRCSOVaoEzzwDDRrY8P+SJaEThffKK3DGGXD44fbnAw8MnUjyUrkQEYlzFSvaCMb559uW4bff\nHjpROE89ZZebNmkCzz9vkzgl/qhciIgkgL32gocegr594YYbICMDdu4MnSp2vIepU20X2XPPtZKh\ny03jl1boFBFJEGlptv/I4YdD797w2WewYAHsvXfoZNH122+2u+l999kS6ePGQalSoVPJnqhciIgk\nmJ49bbGoyy+Hk06yEY169UKnio4vvrBTQe++Cw88AFdcETqRFIZOi4iIJKA2beDNN+3USJMm9lt9\nslm2zD63jRvhtddULBKJyoWISII65hhbYOvSS6FTJ7jqKvj119CpSm7rVhg4EJo3t3U+3n7blkSX\nxKFyISKSwCpUgHnz4N577fTICSck9noYq1bZaMW0aTB+vC2OVb166FRSVCoXIiJJoFMnG8WoUAFO\nPdUmQP7wQ+hUhff77zBmDJx4om3g9vbbNnqhiZuJSeVCRCRJ1K9vW7XfcQcsXGinFBYutMs445X3\n8PjjcNxxcNNNMGiQzSU57rjQyaQkVC6kWDIzM0NHSDk65rGXiMe8VCm4/np4/31o1gzat4czz7SV\nLONNVpatOvr3v8NBB9kOsMcck0nZsqGTSUlFrVw454Y4515zzv3qnPu+CM8b5Zz7yjm3xTn3nHPu\niGhllOJLxG+6iU7HPPYS+ZgfeCAsWgRPP22nR5o3hxYt4MUXw49krFkDV15pcys2bIAnn7QdTY8/\nPrGPufwhmiMXZYCHgJmFfYJzbhBwPdAVOBH4FVjqnFOPFREphvPOs0mSjz0GP/9soxjNm8PixbBt\nW+xy7Nhh79mihZWIF1+E6dNh7Vpo3Rqci10Wib6olQvv/Ujv/TTgnSI87QZgtPf+Se/9u0BHoBZw\nYTQyioikAufs1MPbb9sowY4dcPHFUKMGdOtmu4pGYzTDezvVMWIE1K5t75mdbVe1fPopdO9ukzcl\n+cTNP6tz7nCgBvDCrvu89z8551YAp2CjICIiUkzO2ShB69bwwQdw//22fPjs2XDYYTaq0bQpnHYa\n1K1b9NEE7+Gbb2DFCisxTz0FX31lW8e3awe9ekHDhlH51CTOxE25wIqFBzbmuX9jzsfyUx7g/fff\nj1Is2Z3NmzeTlZUVOkZK0TGPvWQ/5hddZEtrr1plO4wuWwb33GMfq1LFlhSvVs1u++9v/y1dGrZv\nt1Mq27bBli22x8knn9ht82Z7/iGH2LbozZrZaZDSpa18FHQ4k/2Yx5tcPzvLR/J1nS/CWJhzbhww\naA8P8UA97/2HuZ7TCZjqvd+3gNc+BXgVqOW935jr/geBbO99ej7PuwJ4oNCfhIiIiOTV3nu/MFIv\nVtSRi8nAvAIe80kxs2wAHHAAfx69OABYtYfnLQXaA+uBrcV8bxERkVRUHjgM+1kaMUUqF97774Dv\nIhkg12t/6pzbALQE1gI45yoBJwHTC8gUsbYlIiKSYl6P9AtGc52Lg51zDYBDgVLOuQY5twq5HvOB\nc+7vuZ52GzDMOdfGOXcccB/wBbAkWjlFREQksqI5oXMUdinpLrtm6JwB7Forri5QedcDvPcTnXN7\nA7OAKsAy4Dzv/fYo5hQREZEIKtKEThEREZGCaG8RERERiSiVCxEREYmohCgXzrmezrlPnXO/OeeW\nO+dOKODxLZxzK51zW51zH+astSFFUJRj7pxr65x71jn3jXNus3Pudefc2bHMmwyK+nWe63lNnXO/\nO+e08lARFeN7S1nn3Bjn3Pqc7y+fOOc6xyhuUijGMW/vnFudswnmV865uc65Pa6bJH9wzp3unHvc\nOfelcy7bOXdBIZ5T4p+hcV8unHOXAVOAm4GGwBpsM7P983n8YcCT2DLiDYBpwBzn3FmxyJsMinrM\ngWbAs8B5QCPgReCJnKuFpBCKccx3Pa8yMB94Puohk0wxj/kibFL6VcCRQDqwLspRk0Yxvp83xb6+\n7wbqAxdjm1rOjkng5FABWA30wBa63KOI/Qz13sf1DVgOTMv1d4ddnjown8dPANbmuS8TeDr055Io\nt6Ie83xe411gWOjPJVFuxT3mOV/bI7Fv1lmhP49EuhXje8u5wPdAldDZE/VWjGPeD/hPnvuuB/4b\n+nNJxBuQDVxQwGMi8jM0rkcunHNlgMb8eTMzj/2Wdko+TzuZv/4Wt3QPj5dcinnM876GAypi34il\nAMU95s65q4DDsXIhRVDMY94GeBsY5Jz7wjm3zjk3yTkX0T0ZklUxj/kbwMHOufNyXuMA4BLgqeim\nTWkR+Rka1+UC2B8oRdE2M6uRz+MrOefKRTZeUirOMc9rADYUp51sC6fIx9w5VxcYi+0HkB3deEmp\nOF/ntYHTgWOAC4EbsGH6fFcQlj8p8jH33r8OdAAedM5tB74GfsBGLyQ6IvIzNN7LhSSYnI3khgOX\neO83hc6TjJxzadhmfTd77z/edXfASKkiDRtWvsJ7/7b3/hmgL9BJv7hEh3OuPnbOfwQ2n+scbLRu\nVsBYUgjxtOX67mwCdmKbl+V2ALbR2e5syOfxP3nvt0U2XlIqzjEHwDl3OTbR6mLv/YvRiZeUinrM\nKwJNgOOdc7t+a07DzkhtB8723r8UpazJojhf518DX3rvf8l13/tYsTsI+Hi3z5JdinPMBwOvee9v\nzfn7u865HsAy59xQn2sHbYmYiPwMjeuRC+/978BKbDMz4H/n81uS/0Yrb+R+fI6zc+6XAhTzmOOc\nSwfmApfn/EYnhVSMY/4TcCxwPDabuwFwF/BBzp9XRDlywivm1/lrQK2cLQp2OQobzfgiSlGTRjGP\n+d7Ajjz3ZWNXPWi0Ljoi8zM09OzVQsxuvRTYgu1TcjQ2HPYdUC3n4+OA+bkefxjwMzbj9Sjs8pvt\nQKvQn0ui3IpxzK/IOcbXYQ13161S6M8lUW5FPea7eb6uFonyMcfmEX0GPAjUwy7BXgfcFfpzSZRb\nMY55J2BbzveWw4GmwJvA66E/l0S55XzdNsB+GckG+uT8/eB8jnlEfoYG/8QLeXB6AOuB37D21CTX\nx+YB/8rz+GZYQ/4N+A9wZejPIdFuRTnm2LoWO3dzuyf055FIt6J+ned5rspFDI45trbFUuCXnKIx\nESgX+vNIpFsxjnlP4J2cY/4Ftu5FzdCfR6LcgOY5pWK335+j9TNUG5eJiIhIRMX1nAsRERFJPCoX\nIiIiElEqFyIiIhJRKhciIiISUSoXIiIiElEqFyIiIhJRKhciIiISUSoXIiIiElEqFyIiIhJRKhci\nIiISUSoXIiIiElH/D1kQuPl34B8nAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1061eb278>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Matplotlib has a number of plotting tools that are extremely powerful for\n",
    "# exploring data. The plotting functionality is simliar to R, but many times\n",
    "# it is easier of more customizable. \n",
    "# Note: everthying you know in \"R\" will come back full circle. Python and R play very \n",
    "#   nicely with one another and python can call R code, share memory with it, and use its plotting functions\n",
    "#   ...with the correct libraries installed! Check out Rpy2, http://rpy.sourceforge.net \n",
    "\n",
    "%matplotlib inline\n",
    "\n",
    "#============================================\n",
    "# plotting example\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "plt.plot(t, y)  # plot them\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.6.0\n"
     ]
    }
   ],
   "source": [
    "# this library ships with python and is for accessing SQL\n",
    "# You will learn how to use the module more extensively in the future!\n",
    "# here, we will just import it and get its version\n",
    "import sqlite3\n",
    "\n",
    "print (sqlite3.version)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Debugging\n",
    "\n",
    "Debugging in python is much like any other programming language. If you use the command line to run programs, you need to be able to catch and interpret runtime errors. There is no compilation process (that we have talked about), so all errors will occur at runtime--that includes things like spelling errors. Because of this, it is critical to run your code in varying contexts. That also means exploring ways that it could fail by changing the values of different variables.\n",
    "\n",
    "One easy way to do this is by the using the pdb package. You can run it from the iPython notebook, but it gets quite long on the output trace. You will likely want to copy this test over to another document (for example, debugging.py) and run it from the command line (for example, >python debugging.py). The pdb library allows you to set break points in the files and also step through the program, changing the variable values. \n",
    "\n",
    "+ import pdb\n",
    "    + pdb.set_trace()\n",
    "+ command line arguments\n",
    "    + s(tep), c(ontinue), n(ext), w(here), l(ist), r(eturn), j(ump)\n",
    "+ and much more… like print, p, pp\n",
    "+ can set numbered break points by running from python window\n",
    "    + python -m pdb your_function.py "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "> <ipython-input-87-25daee69af4d>(4)<module>()\n",
      "-> for i in range(0,5):\n",
      "(Pdb) c\n",
      "> <ipython-input-87-25daee69af4d>(4)<module>()\n",
      "-> for i in range(0,5):\n",
      "(Pdb) c\n",
      "> <ipython-input-87-25daee69af4d>(4)<module>()\n",
      "-> for i in range(0,5):\n",
      "(Pdb) c\n",
      "> <ipython-input-87-25daee69af4d>(4)<module>()\n",
      "-> for i in range(0,5):\n",
      "(Pdb) c\n",
      "> <ipython-input-87-25daee69af4d>(4)<module>()\n",
      "-> for i in range(0,5):\n",
      "(Pdb) c\n",
      "50\n"
     ]
    }
   ],
   "source": [
    "import pdb\n",
    "\n",
    "j = 0\n",
    "for i in range(0,5):\n",
    "    j += 5*i\n",
    "    pdb.set_trace()\n",
    "    \n",
    "print (j)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is still plenty more to learn about python, but now you have the basics. One topic that may be intersting to you is the concept of decorators, discussed here:\n",
    "    http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/\n",
    "    \n",
    "Essentially, decorators are ways of manipulating functions with other functions. Mostly, this means recycling the functionality of one function to create a new function. \n",
    "\n",
    "There is also much to be learned about iterators, yield, etc. Python is an active language and it is still evolving!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [MLEnv]",
   "language": "python",
   "name": "Python [MLEnv]"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
